--modul odpowiedzialny za mnozenie metoda Bootha

library ieee;
use ieee.std_logic_1164.all; 
use ieee.std_logic_arith.all; 

entity mnoz is
	port (	clk : in std_ulogic;	--bit zegara
	    mnoz_go : in std_ulogic;	--bit startu operacji mnozenia
	     mnoz_a : in std_ulogic_vector ( 7 downto 0);	--mnoznik
	     mnoz_b : in std_ulogic_vector ( 7 downto 0);	--mnozna
	    mnoz_ok : out std_ulogic := '0';	-- bit okreslajacy gotowosc wyniku operacji mnozenia
	    mnoz_wy : out std_ulogic_vector ( 7 downto 0) := x"00"; --bity wyniku operacji mnozenia
	  mnoz_prze : out std_ulogic := '1' --bit przepelnienia (0 oznacza wystapienie przepelnienia, 1 brak przepelnienia)
	);
end entity mnoz;

architecture mnozarch of mnoz is 
	type stan_type is (s0, s1, s2, s3, s4, s5, s6);
	
	signal stan : stan_type; --sygnal stanu automatu mnozacego
	signal a : std_ulogic_vector ( 16 downto 0) := "00000000000000000"; --sygnal grupy bitow A w metodzie Bootha
	signal s : std_ulogic_vector ( 16 downto 0); --sygnal grupy bitow S w metodzie Bootha
	signal p : std_ulogic_vector ( 16 downto 0); --sygnal grupy bitow P w metodzie Bootha
	signal patmp : unsigned (16 downto 0); --sygnal tymczasowy grupy bitow P+A
	signal pstmp : unsigned (16 downto 0); --sygnal tymczasowy grupy bitow P+S
	signal stmp : unsigned (7 downto 0); --sygnal tymczasowy grupy bitow S
	
	signal l : signed (3 downto 0); --sygnal licznika, poczatkowa wartosc integer powodowala bledy z symulacja
	
	begin stan_nast : process (clk) is
		begin
		if rising_edge(clk) then 
		  case stan is 
			 when s0 =>
				mnoz_ok <= '0';
				stmp <=  0 - unsigned (mnoz_a);	--zapisujemy do grupy S odwrocna wartosc mnoznika (-mnoznik) 
				if mnoz_go = '1' then	--na sygnal rozpoczecia mnozenia przechodzimy do kolejnego stanu
					stan <= s1;
				else
					stan <= s0;
				end if;
			when s1 =>
				mnoz_ok <= '0';
				l <= x"8";	--inicjujemy licznik liczba bitow mnoznej
				a <= (mnoz_a & "000000000"); --zapisujemy do grupy A wartosc mnoznika,
			--na symulacji te zera sa prezentowane jako U bo nie korzystamy z tych bitow i sa one optymalizowane
				s <= (std_ulogic_vector (stmp)) & "000000000"; --zapisujemy do grupy S wartosc '-mnozna',
			--podobne jak wyzej uwagi co do symulacji
				p <= "00000000" &  mnoz_b & "0"; --zapisanie do grupy P zer, wartosci mnoznej oraz bitu zero na koncu
				stan <= s2;
			when s2 =>
				mnoz_ok <= '0';
				patmp <= unsigned( p ) + unsigned ( a ); --dodanie wartosci z  grup P i A z ignorowaniem przepelnienia
				pstmp <= unsigned( p ) + unsigned ( s ); --dodanie wartosci z  grup P i S z ignorowaniem przepelnienia
				if l = 0 then
					stan <= s6;
				else	--w zaleznosci od stanu dwoch bitow z grupy P uwzgledniamy powyzsze dodawanie lub nie
					if p (1 downto 0) = "01" then stan <= s3;
					elsif p (1 downto 0) = "10" then stan <= s4;
					elsif p (1 downto 0) = "11" or p (1 downto 0) = "00" then stan <= s5;
					end if;
					l <= l; a <= a; s <= s;	
				end if;
			when s3 =>
				mnoz_ok <= '0';
				p <= std_ulogic_vector ( patmp ); --uwzglednienie sumowania P + A
				l <= l; a <= a; s <= s; 
				stan <= s5;
			when s4 =>				
				mnoz_ok <= '0';
				p <= std_ulogic_vector ( pstmp );  --uwzglednienie sumowania P + S
				l <= l; a <= a; s <= s; 
				stan <= s5;
			when s5 =>
				mnoz_ok <= '0';
				l <= l - 1;	--dekrementacja licznika 
				p <= p(16) & p(16 downto 1);	--przesuniecie arytmetyczne w prawo grupy bitow P
				a <= a; s <= s; 
				stan <= s2;
			when s6 =>
			--sprawdzanie czy gorne 8 bitow grupy P jest takie same (albo same zera albo same jedynki)
			--oznacza to ze wynik (dodatni lub ujemny) zmiesci sie na 8 bitach (nie wystepuje przeniesienie)
				if ((p (16 downto 8) = "000000000") or (p (16 downto 8) = "111111111"))  then
					mnoz_prze <= '1';
				else
					mnoz_prze <= '0';
				end if;
				mnoz_ok <= '1';
				mnoz_wy <= p (8 downto 1 ); --wynikiem mnozenia jest 8 bitow z grupy P 
				if mnoz_go = '0' then
					stan <= s0;
				else
					stan <= s6;
				end if;
		  end case;
 		end if;
	end process stan_nast;

end architecture mnozarch;
